namespace PDUConverter
{
    /// <summary>
    /// Indicates the format of a phone number.
    /// </summary>
    /// <remarks>
    /// The most common value of this octet is 91 hex (10010001 bin), which indicates international format.
    /// A phone number in international format looks like 46708251358 (where the country code is 46).
    /// In the national (or unknown) format the same phone number would look like 0708251358. The international
    /// format is the most generic, and it has to be accepted also when the message is destined to a recipient
    /// in the same country as the MSC or as the SGSN. 
    /// </remarks>
    public class AddressType
    {
        private bool bit7;
        /// <summary>
        /// International number, telephone numbering plan.
        /// </summary>
        public const byte InternationalPhone = 0x91;
        private byte npi;
        private byte ton;
        /// <summary>
        /// Unknown type of number and numbering plan.
        /// </summary>
        public const byte Unknown = 0;
        /// <summary>
        /// Unknown type of number, telephone numbering plan.
        /// </summary>
        public const byte UnknownPhone = 0x81;

        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        public AddressType()
        {
            this.bit7 = true;
            this.ton = 0;
            this.npi = 0;
        }

        /// <summary>
        /// Initializes a new instance of the class using the given value.
        /// </summary>
        /// <param name="toa">The Type-of-Address octet to initialize the object with.</param>
        public AddressType(byte toa)
        {
            this.bit7 = (toa & 0x80) > 0;
            this.ton = (byte) ((toa >> 4) & 7);
            this.npi = (byte) (toa & 15);
        }

        /// <summary>
        /// Converts the value of the specified <see cref="T:GsmComm.PduConverter.AddressType" /> instance into a <see cref="T:System.Byte" />.
        /// </summary>
        /// <param name="a">An <see cref="T:GsmComm.PduConverter.AddressType" /> object.</param>
        /// <returns>A new <see cref="T:System.Byte" /> value representing the object's value.</returns>
        public static implicit operator byte(AddressType a)
        {
            return a.ToByte();
        }

        /// <summary>
        /// Converts the specified <see cref="T:System.Byte" /> value into an <see cref="T:GsmComm.PduConverter.AddressType" /> object.
        /// </summary>
        /// <param name="toa">A <see cref="T:System.Byte" /> value.</param>
        /// <returns>A new <see cref="T:GsmComm.PduConverter.AddressType" /> object whose value equals the value of the
        /// <b>b</b> parameter.</returns>
        public static implicit operator AddressType(byte toa)
        {
            return new AddressType(toa);
        }

        /// <summary>
        /// Returns the byte equivalent of this instance.
        /// </summary>
        /// <returns>The byte value.</returns>
        public byte ToByte()
        {
            return (byte) (((this.bit7 ? 0x80 : 0) | (this.ton << 4)) | this.npi);
        }

        /// <summary>
        /// The Numbering Plan Identification.
        /// </summary>
        /// <remarks>
        /// The Numbering-plan-identification applies for Type-of-number = 000, 001 and 010.
        /// For Type-of-number = 101 bits 3,2,1,0 are reserved and shall be transmitted as 0000.
        /// Note that for addressing any of the entities SC, MSC, SGSN or MS, Numbering-plan-identification = 0001
        /// will always be used. However, for addressing the SME, any specified Numbering-plan-identification
        /// value may be used.
        /// </remarks>
        public byte Npi
        {
            get
            {
                return this.npi;
            }
            set
            {
                this.npi = value;
            }
        }

        /// <summary>
        /// The Type of number.
        /// </summary>
        public byte Ton
        {
            get
            {
                return this.ton;
            }
            set
            {
                this.ton = value;
            }
        }

        /// <summary>
        /// Indicates the Numbering Plan Identification (NPI) of the phone number.
        /// </summary>
        public enum NumberingPlan : byte
        {
            /// <summary>Data numbering plan (X.121).</summary>
            Data = 3,
            /// <summary>ERMES numbering plan (ETSI DE/PS 3 01-3).</summary>
            Ermes = 10,
            /// <summary>National numbering plan.</summary>
            National = 8,
            /// <summary>Private numbering plan.</summary>
            Private = 9,
            /// <summary>Reserved for extension.</summary>
            Reserved = 15,
            /// <summary>ISDN/telephone numbering plan (E.164/E.163).</summary>
            Telephone = 1,
            /// <summary>Telex numbering plan.</summary>
            Telex = 4,
            /// <summary>Unknown</summary>
            Unknown = 0
        }

        /// <summary>
        /// Indicates the type of the phone number (TON).
        /// </summary>
        public enum TypeOfNumber : byte
        {
            /// <summary>Abbreviated number.</summary>
            Abbreviated = 6,
            /// <summary>Alphanumeric, (coded according to GSM TS 03.38 7-bit default alphabet).</summary>
            Alphanumeric = 5,
            /// <summary>International number.</summary>
            International = 1,
            /// <summary>National number. Prefix or escape digits shall not be included.</summary>
            National = 2,
            /// <summary>
            /// Network specific number. This is used to indicate administration/service number specific
            /// to the serving network, e.g. used to access an operator.
            /// </summary>
            NetworkSpecific = 3,
            /// <summary>Reserved for extension.</summary>
            Reserved = 7,
            /// <summary>
            /// Subscriber number. This is used when a specific short number representation is stored
            /// in one or more SCs as part of a higher layer application. (Note that "Subscriber number"
            /// shall only be used in connection with the proper PID referring to this application). 
            /// </summary>
            Subscriber = 4,
            /// <summary>
            /// Unknown. This is used when the user or network has no a priori information about the numbering plan.
            /// In this case, the Address-Value field is organized according to the network dialling plan,
            /// e.g. prefix or escape digits might be present.
            /// </summary>
            Unknown = 0
        }
    }
}